package com.eurasia.assignment.controller;

import com.eurasia.assignment.domain.User;
import com.eurasia.assignment.domain.UserRole;
import com.eurasia.assignment.security.JwtTokenUtil;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import static org.hamcrest.Matchers.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
@Transactional
@Sql("/sql/classes.sql") // 所有测试方法都会使用这个SQL脚本
public class FindClassesTest {

    @Autowired
    private MockMvc mockMvc;
    
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    
    private String jwtToken;
    
    @BeforeEach
    public void setup() {
        // 创建一个模拟用户并生成JWT令牌
        User testUser = new User();
        testUser.setUsername("testuser");
        testUser.setRole(UserRole.TEACHER); // 使用TEACHER角色
        
        // 生成JWT令牌
        jwtToken = jwtTokenUtil.generateToken(testUser);
    }

    /**
     * 测试带全部参数的分页班级查询
     * - 包含班级名称、年级、专业、班主任、页码、每页大小、排序字段和排序方向
     */
    @Test
    public void should_find_paged_class_successfully() throws Exception {
        // 构建查询参数
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("className", "计算机");
        params.add("grade", "2020");
        params.add("major", "计算机科学与技术");
        params.add("tutor", "张教授");
        params.add("page", "0");
        params.add("size", "5");
        params.add("sortBy", "id");
        params.add("sortDirection", "asc");
        
        // 构建请求并添加Authorization头
        MockHttpServletRequestBuilder request = get("/classes")
                .contentType(MediaType.APPLICATION_JSON)
                .header("Authorization", "Bearer " + jwtToken)
                .params(params);
        
        // 执行请求并验证结果
        mockMvc.perform(request)
                .andDo(MockMvcResultHandlers.print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.totalElements", greaterThanOrEqualTo(1)))
                .andExpect(jsonPath("$.content", hasSize(lessThanOrEqualTo(5))))
                .andExpect(jsonPath("$.content[0].className", containsString("计算机")))
                .andExpect(jsonPath("$.content[0].grade", is("2020")))
                .andExpect(jsonPath("$.content[0].major", is("计算机科学与技术")))
                .andExpect(jsonPath("$.content[0].tutor", is("张教授")));
    }
    
    /**
     * 测试带部分参数的分页班级查询
     * - 仅包含年级和专业，不包含其他可选参数
     */
    @Test
    public void should_find_paged_class_with_partial_params_successfully() throws Exception {
        // 构建查询参数，只包含部分参数
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("grade", "2022");
        params.add("major", "软件工程");
        
        // 构建请求并添加Authorization头
        MockHttpServletRequestBuilder request = get("/classes")
                .contentType(MediaType.APPLICATION_JSON)
                .header("Authorization", "Bearer " + jwtToken)
                .params(params);
        
        // 执行请求并验证结果
        mockMvc.perform(request)
                .andDo(MockMvcResultHandlers.print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.totalElements", greaterThanOrEqualTo(1)))
                .andExpect(jsonPath("$.content[0].grade", is("2022")))
                .andExpect(jsonPath("$.content[0].major", is("软件工程")));
    }
    
    /**
     * 测试不带任何参数的班级查询
     * - 使用默认分页和排序参数
     */
    @Test
    public void should_find_all_classes_with_default_pagination_successfully() throws Exception {
        // 构建请求并添加Authorization头
        MockHttpServletRequestBuilder request = get("/classes")
                .contentType(MediaType.APPLICATION_JSON)
                .header("Authorization", "Bearer " + jwtToken);
        
        // 执行请求并验证结果
        mockMvc.perform(request)
                .andDo(MockMvcResultHandlers.print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.totalElements", is(15))) // 总共15条记录
                .andExpect(jsonPath("$.content", hasSize(10))); // 默认每页10条
    }
    
    /**
     * 测试特定分页参数的班级查询
     * - 设置分页为第2页，每页5条记录
     */
    @Test
    public void should_find_paged_class_with_pagination_params_successfully() throws Exception {
        // 构建查询参数，只包含分页参数
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("page", "1"); // 第二页，索引从0开始
        params.add("size", "5"); // 每页5条记录
        
        // 构建请求并添加Authorization头
        MockHttpServletRequestBuilder request = get("/classes")
                .contentType(MediaType.APPLICATION_JSON)
                .header("Authorization", "Bearer " + jwtToken)
                .params(params);
        
        // 执行请求并验证结果
        mockMvc.perform(request)
                .andDo(MockMvcResultHandlers.print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.totalElements", is(15))) // 总共15条记录
                .andExpect(jsonPath("$.content", hasSize(5))) // 每页5条
                .andExpect(jsonPath("$.page", is(1))); // 当前是第二页（索引为1）
    }
} 